#ifndef _ASM_IO_H
#define _ASM_IO_H

#include <linux/config.h>

/*
 * This file contains the definitions for the x86 IO instructions
 * inb/inw/inl/outb/outw/outl and the "string versions" of the same
 * (insb/insw/insl/outsb/outsw/outsl). You can also use "pausing"
 * versions of the single-IO instructions (inb_p/inw_p/..).
 *
 * This file is not meant to be obfuscating: it's just complicated
 * to (a) handle it all in a way that makes gcc able to optimize it
 * as well as possible and (b) trying to avoid writing the same thing
 * over and over again with slight variations and possibly making a
 * mistake somewhere.
 */

/*
 * Thanks to James van Artsdalen for a better timing-fix than
 * the two short jumps: using outb's to a nonexistent port seems
 * to guarantee better timings even on fast machines.
 *
 * On the other hand, I'd like to be sure of a non-existent port:
 * I feel a bit unsafe about using 0x80 (should be safe, though)
 *
 *		Linus
 */

 /*
  *  Bit simplified and optimized by Jan Hubicka
  *  Support of BIGMEM added by Gerhard Wichert, Siemens AG, July 1999.
  *
  *  isa_memset_io, isa_memcpy_fromio, isa_memcpy_toio added,
  *  isa_read[wl] and isa_write[wl] fixed
  *  - Arnaldo Carvalho de Melo <acme@conectiva.com.br>
  */

#ifdef SLOW_IO_BY_JUMPING
#define __SLOW_DOWN_IO __asm { db 0xeb, 0, 0xeb, 0 } 
#else
#define __SLOW_DOWN_IO __asm { out 0x80, al }
#endif

#ifdef REALLY_SLOW_IO
#define __FULL_SLOW_DOWN_IO __SLOW_DOWN_IO __SLOW_DOWN_IO __SLOW_DOWN_IO __SLOW_DOWN_IO
#else
#define __FULL_SLOW_DOWN_IO __SLOW_DOWN_IO
#endif

/*
 * Talk about misusing macros..
 */
#define __OUT1(s, s2, x) \
static __fastcall void out##s(unsigned x value, unsigned short port) { \
__asm { out dx, s2 }

#define __OUT2 \
}

#define __OUT(s,s2,x) \
__OUT1(s,s2,x) __OUT2 \
__OUT1(s##_p,s2,x) __FULL_SLOW_DOWN_IO __OUT2 \

#define __IN1(s,s2) \
static __fastcall RETURN_TYPE in##s(unsigned short port) { RETURN_TYPE _v; \
  __asm { mov edx, eax; in s2, dx; mov _v, s2 }

#define __IN2 \
return _v; }

#define __IN(s,s2) \
__IN1(s,s2) __IN2 \
__IN1(s##_p,s2) __FULL_SLOW_DOWN_IO __IN2 \


#define __INS(s, s2) \
static __fastcall void ins##s(unsigned short port, void * addr, unsigned long count) \
{ __asm { mov esi, edx; mov edx, eax; mov dx, ax; rep ins##s2; } }

#define __OUTS(s, s2) \
static __fastcall void outs##s(unsigned short port, const void * addr, unsigned long count) \
{ __asm { mov edi, edx; mov edx, eax; mov dx, ax; rep outs##s2; } }

#define RETURN_TYPE unsigned char
__IN(b,al)
#undef RETURN_TYPE
#define RETURN_TYPE unsigned short
__IN(w,ax)
#undef RETURN_TYPE
#define RETURN_TYPE unsigned int
__IN(l,eax)
#undef RETURN_TYPE

__OUT(b,al,char)
__OUT(w,ax,short)
__OUT(l,eax,int)

__INS(b,b)
__INS(w,w)
__INS(l,d)

__OUTS(b,b)
__OUTS(w,w)
__OUTS(l,d)

#define IO_SPACE_LIMIT 0xffff


#endif
 